﻿using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System;
using System.Collections.Immutable;
using System.Threading;

namespace DimensionsHelper.SourceGeneration.CommandLine
{

    [Generator(LanguageNames.CSharp)]
    public sealed partial class ArgumentSourceGenerator : IIncrementalGenerator
    {
        public Action<GenerationInfo> OnSourceEmitting;

        // public void Execute(GeneratorExecutionContext context)
        // {
        //     if (!(context.SyntaxContextReceiver is SyntaxContextReceiver receiver) ||
        //         receiver.ContextClassDeclarations is null)
        //     {
        //         return;
        //     }
        // 
        //     var parser = new Parser(context.Compilation);
        // 
        //     foreach (var item in receiver.ContextClassDeclarations)
        //     {
        //         var info = parser.ParseContextGenerationInfo(item.Item1, item.Item2, CancellationToken.None);
        //         if (info != null)
        //         {
        //             OnSourceEmitting?.Invoke(info);
        //             ArgumentSourceEmitter.Emit(context, info);
        //         }
        //     }
        // 
        //     foreach (var diag in parser.Diagnostics)
        //     {
        //         context.ReportDiagnostic(Diagnostic.Create(diag.Descriptor, diag.Location, diag.MessageArgs));
        //     }
        // }

        // public void Initialize(GeneratorInitializationContext context)
        // {
        //     context.RegisterForSyntaxNotifications(() => new SyntaxContextReceiver(Parser.ArgumentContextAttributeFullName, CancellationToken.None));
        // }

        private static bool PredicateNode(SyntaxNode node, CancellationToken token)
        {
            return node is ClassDeclarationSyntax classDeclaration
                && !classDeclaration.Modifiers.Any(SyntaxKind.AbstractKeyword)
                && (classDeclaration.Modifiers.Any(SyntaxKind.PublicKeyword) || classDeclaration.Modifiers.Any(SyntaxKind.InternalKeyword))
                && classDeclaration.AttributeLists.Count > 0;
        }


        public void Initialize(IncrementalGeneratorInitializationContext context)
        {

            IncrementalValuesProvider<(GenerationInfo GenInfo, ImmutableArray<DiagnosticInfo> Diagnostics)> classDecarationWithModel =
                context.SyntaxProvider
                .ForAttributeWithMetadataName(
                    Parser.ArgumentContextAttributeFullName,
                    PredicateNode,
                    (ctx, _) => (ContextClass: (ClassDeclarationSyntax)ctx.TargetNode, ctx.SemanticModel))
                .Select((tuple, cancellationToken) =>
                {
                    var parser = new Parser(tuple.SemanticModel.Compilation);
                    var info = parser.ParseContextGenerationInfo(tuple.ContextClass, tuple.SemanticModel, cancellationToken);
                    var diags = parser.Diagnostics.ToImmutableArray();
                    return (info, diags);
                })
                .WithTrackingName("GenerationInfo");

            context.RegisterSourceOutput(classDecarationWithModel, (ctx, source) =>
            {
                foreach (var diag in source.Diagnostics)
                {
                    ctx.ReportDiagnostic(Diagnostic.Create(diag.Descriptor, diag.Location, diag.MessageArgs));
                }

                if (source.GenInfo is null)
                {
                    return;
                }

                OnSourceEmitting?.Invoke(source.GenInfo);
                ArgumentSourceEmitter.Emit(ctx, source.GenInfo);
            });
        }

    }
}